package com.example.demo1

import com.example.demo1.IntListEq.eq
import com.example.util.p


interface Eq<F>{
    fun F.eq(that:F):Boolean
}

object IntEq:Eq<Int>{
    override fun Int.eq(that: Int): Boolean {
        return this == that
    }

}


fun main(){

    IntEq.run {
        val a = 1
        p(a.eq(1))
        p(a.eq(2))
    }

    val a = Cons(1,Cons(2,Nil))
    p(a.eq(Cons(1,Cons(2,Nil))))
    p(a.eq(Cons(1,Nil)))

    BookShow.run {
        p(Book("Dive Into Kotlin").show())
    }

    BookListShow.run {
        p(Cons(Book("Dive into Kotlin"),Cons(Book("Thinking in Java"),Nil)).show())

    }

    val b = fun(){
      p("test")
    }

    b
    b()

}




abstract class ListEq<A>(private val a:Eq<A>):Eq<Kind<List.K,A>>{
    override fun Kind<List.K, A>.eq(that: Kind<List.K, A>): Boolean {
        val curr = this
        return if(curr is Cons && that is Cons){
            val headEq = a.run {
                curr.head.eq(that.head)
            }
            if(headEq)curr.tail.eq(that.tail)else false
        }else curr is Nil && that is Nil
    }
}

object IntListEq:ListEq<Int>(IntEq)


interface Show<F>{
    fun F.show():String
}

class Book(val name:String)

object BookShow:Show<Book>{
    override fun Book.show()=this.name

}


interface Foldable<F>{
    fun <A,B> Kind<F,A>.fold(init:B):((B,A)->B)->B
}


object ListFoldable:Foldable<List.K>{
    override fun <A, B> Kind<List.K, A>.fold(init: B): ((B, A) -> B) -> B = {
        f->fun fold0(l:List<A>,v:B):B{
            return when(l){
                is Cons->{
                    fold0(l.tail,f(v,l.head))
                }
                else -> v
            }
        }
        fold0(this.unwrap(),init)
    }

}


abstract class ListShow<A>(private val a:Show<A>):Show<Kind<List.K,A>>{
    override fun Kind<List.K, A>.show(): String {
        val fa = this
        return "["+ListFoldable.run {
            fa.fold(listOf<String>())({ r, i ->
                r + a.run { i.show() }
            }).joinToString()+"]"
        }


    }
}

object BookListShow:ListShow<Book>(BookShow)


































